package com.shanjupay.merchant.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shanjupay.common.domain.BusinessException;
import com.shanjupay.common.domain.CommonErrorCode;
import com.shanjupay.common.util.PhoneUtil;
import com.shanjupay.merchant.api.MerchantService;
import com.shanjupay.merchant.api.dto.MerchantDTO;
import com.shanjupay.merchant.api.dto.StaffDTO;
import com.shanjupay.merchant.api.dto.StoreDTO;
import com.shanjupay.merchant.convert.MerchantConvert;
import com.shanjupay.merchant.convert.StaffConvert;
import com.shanjupay.merchant.convert.StoreConvert;
import com.shanjupay.merchant.entity.Merchant;
import com.shanjupay.merchant.entity.Staff;
import com.shanjupay.merchant.entity.Store;
import com.shanjupay.merchant.entity.StoreStaff;
import com.shanjupay.merchant.mapper.MerchantMapper;
import com.shanjupay.merchant.mapper.StaffMapper;
import com.shanjupay.merchant.mapper.StoreMapper;
import com.shanjupay.merchant.mapper.StoreStaffMapper;
import com.shanjupay.user.api.TenantService;
import com.shanjupay.user.api.dto.tenant.CreateTenantRequestDTO;
import com.shanjupay.user.api.dto.tenant.TenantDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author whb
 * @create 2021-11-15 20:54
 * @decription
 */
@Service
@Slf4j
public class MerchantServiceImpl implements MerchantService {
    @Autowired
    private MerchantMapper merchantMapper;//商户mapper
    @Autowired
    private StoreMapper storeMapper;//门店mapper
    @Autowired
    private StaffMapper staffMapper;//员工mapper
    @Autowired
    private StoreStaffMapper storeStaffMapper;//门店和员工关系mapper
    @Reference
    private TenantService tenantService;//SaaS提供的dubbo服务，用于创建租户和用户，以及其关系

    /**
     * 根据 id查询商户
     * @param id
     * @return
     */
    @Override
    public MerchantDTO queryMerchantById(Long id) {
        Merchant merchant = merchantMapper.selectById(id);

        /*MerchantDTO merchantDTO = new MerchantDTO();
        if (merchant!=null){
            merchantDTO.setId(merchant.getId());
            merchantDTO.setMerchantName(merchant.getMerchantName());
        }*/

        return MerchantConvert.INSTANCE.entity2dto(merchant);
    }

    /**
     * 注册商户服务接口，接收账号、密码和手机号，为了可扩展性使用MerchantDTO接收数据
     * @param merchantDTO 商户注册信息
     * @return 注册成功的商户信息
     */
    @Override
    @Transactional
    public MerchantDTO addMerchant(MerchantDTO merchantDTO) throws RuntimeException {

        //传入对象非空校验
        if (merchantDTO==null){
            throw new BusinessException(CommonErrorCode.E_100108);
        }

        //手机号非空校验
        if (StringUtils.isBlank(merchantDTO.getMobile())){
            throw new BusinessException(CommonErrorCode.E_100112);
        }

        //手机号合法性校验
        if (!PhoneUtil.isMatches(merchantDTO.getMobile())){
            throw new BusinessException(CommonErrorCode.E_100109);
        }

        //联系人非空校验
        /*if (StringUtils.isBlank(merchantDTO.getUsername())){
            throw new BusinessException(CommonErrorCode.E_100110);
        }*/

        //密码非空校验
        if (StringUtils.isBlank(merchantDTO.getPassword())){
            throw new BusinessException(CommonErrorCode.E_100111);
        }

        //手机号唯一性校验
        LambdaQueryWrapper<Merchant> queryWrapper=new LambdaQueryWrapper<Merchant>()
                .eq(Merchant::getMobile, merchantDTO.getMobile());
        Integer count = merchantMapper.selectCount(queryWrapper);
        if (count>0){
            throw new BusinessException(CommonErrorCode.E_100113);
        }

        /**
         * 调用SaaS接口，完成租户，用户和其关系的绑定
         * 新建租户需要调用的参数
         * 1、手机号
         * 2、账号
         * 3、密码
         * 4、租户类型：shanju-merchant
         * 5、默认套餐：shanju-merchant
         * 6、租户名称，同账号名
         */
        CreateTenantRequestDTO createTenantRequestDTO = new CreateTenantRequestDTO();
        createTenantRequestDTO.setMobile(merchantDTO.getMobile());//手机号
        createTenantRequestDTO.setUsername(merchantDTO.getUsername());//账号/员工用户名/用户名
        createTenantRequestDTO.setPassword(merchantDTO.getPassword());//密码
        createTenantRequestDTO.setTenantTypeCode("shanju-merchant");//租户类型
        createTenantRequestDTO.setBundleCode("shanju-merchant");//套餐，根据套餐进行分配权限
        createTenantRequestDTO.setName(merchantDTO.getUsername());//租户名称，和账号名一样

        //如果租户在SaaS已经存在，SaaS直接 返回此租户的信息，否则进行添加
        TenantDTO tenantAndAccount = tenantService.createTenantAndAccount(createTenantRequestDTO);
        if (tenantAndAccount==null || tenantAndAccount.getId()==null){
            throw new BusinessException(CommonErrorCode.E_200012);
        }
        Long tenantId = tenantAndAccount.getId();//租户id

        //商户表中租户唯一性校验：如果存在该租户，则不允许再添加商户
        Integer countTenant = merchantMapper.selectCount(new LambdaQueryWrapper<Merchant>().eq(Merchant::getTenantId, tenantId));
        if (countTenant>0){
            throw new BusinessException(CommonErrorCode.E_200017);
        }

        //Merchant merchant = new Merchant();

        //通过MapStuct工程将dto数据类型转成entity数据类型，简化两种数据类型之间的转换
        Merchant merchant = MerchantConvert.INSTANCE.dto2entity(merchantDTO);

        //商户绑定租户id（平台商户和SaaS租户一对一）
        merchant.setTenantId(tenantId);
        //设置审核状态0‐未申请,1‐已申请待审核,2‐审核通过,3‐审核拒绝
        merchant.setAuditStatus("0");
        //设置手机号
        //merchant.setMobile(merchantDTO.getMobile());
        //保存商户
        merchantMapper.insert(merchant);

        //新增门店
        StoreDTO storeDTO = new StoreDTO();
        storeDTO.setStoreName("根门店");//门店名称
        storeDTO.setMerchantId(merchant.getId());//所属商户id
        StoreDTO store = createStore(storeDTO);

        //新增员工
        StaffDTO staffDTO = new StaffDTO();
        staffDTO.setMerchantId(merchant.getId());//员工所属商户id
        staffDTO.setMobile(merchantDTO.getMobile());//手机号（关联统一用户）
        staffDTO.setUsername(merchantDTO.getUsername());//用户名（关联统一用户）
        staffDTO.setStoreId(store.getId());//员工所属门店id
        StaffDTO staff = createStaff(staffDTO);

        //为门店设置管理员（默认商户注册时的员工就是本门店的管理员）
        bindStaffToStore(store.getId(), staff.getId());

        //将新增商户id返回
        //merchantDTO.setId(merchant.getId());

        return MerchantConvert.INSTANCE.entity2dto(merchant);
    }

    /**
     * 资质申请
     * @param merchantId 商户id
     * @param merchantDTO 资质申请信息
     * @throws BusinessException
     */
    @Override
    public void applyMerchantv(Long merchantId, MerchantDTO merchantDTO) throws BusinessException {
        if (merchantId==null || merchantDTO==null){
            throw new BusinessException(CommonErrorCode.E_100108);
        }

        //校验merchantId合法性，查询商户表，如果查询不到记录，认定为非法
        Merchant merchant = merchantMapper.selectById(merchantId);
        if (merchant==null){
            throw new BusinessException(CommonErrorCode.E_200002);
        }

        merchantDTO.setId(merchant.getId());
        merchantDTO.setMobile(merchant.getMobile());//因为资质申请的时候手机号不让改，还使用数据库中原来的手机号
        merchantDTO.setAuditStatus("1");//审核状态1-已申请待审核
        merchantDTO.setTenantId(merchant.getTenantId());

        //将dto转换成entity
        Merchant updateMerchant = MerchantConvert.INSTANCE.dto2entity(merchantDTO);
        //调用mapper更新商户表
        merchantMapper.updateById(updateMerchant);
    }

    /**
     * 新增门店
     * @param storeDTO 新增门店信息
     * @return 新增成功后的门店信息
     * @throws BusinessException
     */
    @Override
    public StoreDTO createStore(StoreDTO storeDTO) throws BusinessException {
        Store store = StoreConvert.INSTANCE.dto2entity(storeDTO);//dto转换成entity
        log.info("新增门店：{}", JSON.toJSONString(store));//在日志中输出新增门店信息
        storeMapper.insert(store);//保存门店信息到数据库
        return StoreConvert.INSTANCE.entity2dto(store);//返回新增成功后门店的信息
    }

    /**
     * 新增员工
     * @param staffDTO 新增员工信息
     * @return 新增成功后的员工信息
     * @throws BusinessException
     */
    @Override
    public StaffDTO createStaff(StaffDTO staffDTO) throws BusinessException {
        //校验参数合法性
        if (staffDTO==null || StringUtils.isBlank(staffDTO.getUsername()) || StringUtils.isBlank(staffDTO.getMobile()) || staffDTO.getStoreId()==null){
            throw new BusinessException(CommonErrorCode.E_300009);
        }
        //在同一商户下员工的用户名唯一
        Boolean existStaffByUserName = isExistStaffByUserName(staffDTO.getMerchantId(), staffDTO.getUsername());
        if (existStaffByUserName){
            throw new BusinessException(CommonErrorCode.E_100114);
        }

        //在同一商户下员工的手机号唯一
        Boolean existStaffByMobile = isExistStaffByMobile(staffDTO.getMerchantId(),staffDTO.getMobile());
        if (existStaffByMobile){
            throw new BusinessException(CommonErrorCode.E_100113);
        }

        Staff staff = StaffConvert.INSTANCE.dto2entity(staffDTO);//员工dto转换entity
        staffMapper.insert(staff);//保存员工信息到数据库

        return StaffConvert.INSTANCE.entity2dto(staff);//返回新增成功后的员工信息
    }

    /**
     * 商户手机号码唯一性校验
     * @param merchantId 商户id
     * @param mobile 用户手机号码
     * @return
     */
    private Boolean isExistStaffByMobile(Long merchantId, String mobile) {
        Integer count = staffMapper.selectCount(new LambdaQueryWrapper<Staff>().eq(Staff::getMerchantId, merchantId).eq(Staff::getMobile, mobile));
        return count>0;
    }

    /**
     * 商户用户名唯一性校验
     * @param merchantId 商户id
     * @param username 用户名
     * @return
     */
    private Boolean isExistStaffByUserName(Long merchantId, String username) {
        Integer count = staffMapper.selectCount(new LambdaQueryWrapper<Staff>().eq(Staff::getMerchantId, merchantId).eq(Staff::getUsername, username));
        return count>0;
    }

    /**
     * 将员工设置为门店的管理员
     * @param storeId 员工id
     * @param staffId 门店id
     * @throws BusinessException
     */
    @Override
    public void bindStaffToStore(Long storeId, Long staffId) throws BusinessException {
        StoreStaff storeStaff = new StoreStaff();//创建门店和员工关系对象
        storeStaff.setStaffId(staffId);//设置员工id
        storeStaff.setStoreId(storeId);//设置门店id
        storeStaffMapper.insert(storeStaff);
    }

    /**
     * 根据租户查询商户
     * @param tenantId 租户id
     * @return 商户信息
     * @throws BusinessException
     */
    @Override
    public MerchantDTO queryMerchantByTenantId(Long tenantId) throws BusinessException {
        Merchant merchant = merchantMapper.selectOne(new LambdaQueryWrapper<Merchant>().eq(Merchant::getTenantId, tenantId));//根据租户id查询商户entity
        return MerchantConvert.INSTANCE.entity2dto(merchant);
    }
}
